// Haxzs Audio Server
// made by omghaxzs
// 2010

#include "dest.h"
#include "log.h"
#include "source.h"
#include "sourcewnd.h"
#include "clientwnd.h"
#include "net.h"

dest::dest() : listensocket(io_service, tcp::endpoint(tcp::v4(), 81)), clientsocket(io_service)
{
	l->printMsg("Initializing Client Listening server...", false);

	// Set up the source server (boost.asio)
	setUpDestServer();

	l->printMsg("done.", true);
}

void dest::setUpDestServer()
{
	// Set up the listening server
	// TODO: Error checking
	listensocket.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
}

void dest::listenForClients()
{
	// Initialize our monitoring thread
	m_MonitorThread = boost::thread(&dest::monitorSource, this);

	// Initialize our client monitoring thread
	m_ClientThread = boost::thread(&dest::monitorClients, this);

	while(true)
	{
		// Listen!
		listensocket.listen();

		// Use blocking to wait for a connection
		client *c = new client();
		listensocket.accept(c->clientsocket);

		// Write to the log
		l->printMsg("New Client Connected, identifing...", true);

		// Create a new client object

		c->cache = s->src->cache;

		c->id = clients.size();

		// Start communicating
		c->start();

		// Add the client to the list of clients
		clients.push_back(c);

		// Update listener count
		clwnd->UpdateListenerCount(clients.size());
	}
}

void dest::monitorSource()
{
	while(true)
	{	
		if (s->connected)
		{
			try
			{
				data = s->src->recvData();
				s->src->processCache(data);
				s->src->bytes += data.size();
				srcwnd->updateSourceBytes(s->src->bytes);
				s->sendInfo();
				for(int i = 0; i < this->clients.size(); i++)
				{
					if (this->clients[i]->getClientType() != CLIENT_TYPE_SOURCE)
					{
						this->clients[i]->okaytosend = false;
						this->clients[i]->processCache(data);
						this->clients[i]->okaytosend = true;
					}
				}
			}
			catch(std::exception& e)
			{
				l->printMsg(e.what(), true);
			}
		}
		Sleep(10);
	}
}

void dest::monitorClients()
{
	while (true)
	{
		// We need to check to see if any of our clients received any errors
		for(int i = 0; i < this->clients.size(); i++)
		{
			if (this->clients[i]->errorcode != 0)
			{
				try
				{
					// Is the client the source?
					if (this->clients[i]->getClientType() == CLIENT_TYPE_SOURCE)
					{
						s->connected = false;
						srcwnd->clearSourceInfo();
						l->printMsg("Source was disconnected! Disconnecting all clients...", true);

						// Disconnect the source
						this->clients[0]->disconnect();
						delete this->clients[0];
						this->clients.erase(this->clients.begin());

						// Yep, we have to disconnect all the clients
						disconnectAllClients();
					}
					else
					{
						if (this->clients[i]->clientsocket.is_open())
						{
							this->clients[i]->disconnect();
						}
						delete this->clients[i];
						this->clients.erase(this->clients.begin() + i);

						// Update listener count
						clwnd->UpdateListenerCount(clients.size());
					}
				}
				catch(std::exception& e)
				{
					l->printMsg(e.what(), true);
				}
			}
		}
		Sleep(1000);
	}
}

void dest::disconnectAllClients()
{
	for(int i = 0; i < this->clients.size(); i++)
	{
		try
		{
			if (this->clients[i]->clientsocket.is_open())
			{
				this->clients[i]->disconnect();
			}
			delete this->clients[i];
			this->clients.erase(this->clients.begin() + i);

			// Update listener count
			clwnd->UpdateListenerCount(clients.size());
		}
		catch(std::exception& e)
		{
			l->printMsg(e.what(), true);
		}
	}

	s->listenForClients();
}
